package team.stride.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.Random;
import java.util.Scanner;

import team.stride.Stride;
import team.stride.database.StrideDB;
import team.stride.database.crud.music.MusicItem;
import team.stride.database.crud.playlists.PlaylistsItem;
import team.stride.database.crud.tracks.TracksItem;
import team.stride.database.crud.users.UsersItem;
import team.stride.gmap.GePoint;
import team.stride.tabs.records.MapListViewItem;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.http.AccessToken;
import twitter4j.http.RequestToken;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;

import com.facebook.android.AsyncFacebookRunner;
import com.facebook.android.BaseRequestListener;
import com.facebook.android.Facebook;
import com.facebook.android.SessionEvents;
import com.facebook.android.SessionStore;
import com.facebook.android.SessionEvents.AuthListener;
import com.facebook.android.SessionEvents.LogoutListener;

public class UtilsStride
{
	public static final double GEO_CONV = 1E6;
	public static final boolean TEST_GPX = true;

	public static ArrayList<GePoint> pathPoints = new ArrayList<GePoint>();
	public static String runningName = "Today Track";
	public static String userName = "";
	public static boolean isMusic = false;

	public static long totalDistance = 0;
	public static long totalTime = 0;
	public static boolean resultsChanged = true;

	public static Stride mainActivity;
	public static SharedPreferences preferences;

	// twitter connection
	public static final String OAUTH_KEY = "grnMGimSBvEb06QE3i8gA";
	public static final String OAUTH_SECRET = "v3NbsYqi7qAXGTaHzh8QNbOQNRkSpuwpdm5rdx4gXhs";
	public static Twitter twitter;
	public static RequestToken requestToken;
	public static AccessToken accessToken;
	public static Boolean isTwitterConnected = new Boolean(false);
	public static Boolean isFacebookConnected = new Boolean(false);

	// facebook connection
	public static Facebook mFacebook;
	public static AsyncFacebookRunner mAsyncRunner;
	private static SessionListener mSessionListener = new SessionListener();

	public static final String APP_ID_FACEBOOK = "172661862769164";

	public static final int TWITTER_WHO = 0;
	public static final int FACEBOOK_WHO = 1;
	public static String fbName = "";
	public static MediaPlayer mp = null;
	public static String currentMP = null;

	public static void readPathFile(FileInputStream fileInput)
	{

		ArrayList<GePoint> path = new ArrayList<GePoint>();

		Scanner scanner = new Scanner(fileInput);
		try
		{
			while (scanner.hasNextInt())
			{
				if (scanner.hasNextInt())
				{
					GePoint point = new GePoint();
					point.setLat(scanner.nextInt());
					point.setLong(scanner.nextInt());

					path.add(point);
				}
				else
					break;
			}
			scanner.close();

		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		// return path;
		pathPoints = path;
	}

	public static void writePathFile(FileOutputStream fileOutput)
	{
		int i;
		String lat, lon;
		PrintWriter printer = new PrintWriter(fileOutput);
		for (i = 0; i < pathPoints.size(); i++)
		{
			lat = "" + pathPoints.get(i).getLat() + " ";
			lon = "" + pathPoints.get(i).getLong() + " ";
			printer.println(lat);
			printer.println(lon);
		}
		printer.close();
	}

	public static void rememberLastTwitterConnection()
	{
		new Thread(new Runnable()
		{
			@Override
			public void run()
			{
				synchronized (isTwitterConnected)
				{
					if (isTwitterConnected)
						return;
					String token = preferences.getString("token_twitter", "");
					String token_secret = preferences.getString("secret_token_twitter", "");

					if (token != "" && token_secret != "")
					{
						try
						{
							accessToken = new AccessToken(token, token_secret);
							twitter = new TwitterFactory().getOAuthAuthorizedInstance(OAUTH_KEY, OAUTH_SECRET,
									accessToken);
							synchronized (isTwitterConnected)
							{
								isTwitterConnected = true;
							}
						}
						catch (Exception e)
						{
							e.printStackTrace();
							storeAccessToken(TWITTER_WHO, "", "");
						}
					}
				}

			}
		}).start();
	}

	public static void rememberLastFacebookConnection()
	{
		synchronized (isFacebookConnected)
		{
			if (isFacebookConnected)
				return;

			if (mFacebook != null)
			{
				if (mFacebook.isSessionValid())
				{
					System.out.println("truuue");
					isFacebookConnected = true;
					return;
				}
			}
			else
			{
				mFacebook = new Facebook(APP_ID_FACEBOOK);
				mAsyncRunner = new AsyncFacebookRunner(mFacebook);

				SessionEvents.addAuthListener(mSessionListener);
				SessionEvents.addLogoutListener(mSessionListener);

				isFacebookConnected = SessionStore.restore(mFacebook, mainActivity);
			}
		}
	}

	public static void storeAccessToken(int who, String token, String token_secret)
	{
		synchronized (preferences)
		{
			SharedPreferences.Editor editor = preferences.edit();
			if (who == TWITTER_WHO)
			{
				editor.putString("token_twitter", token);
				editor.putString("secret_token_twitter", token_secret);
			}
			editor.commit();
		}
	}

	public static void disconnectTwitter()
	{
		storeAccessToken(TWITTER_WHO, "", "");
		userName = "";
		synchronized (isTwitterConnected)
		{
			isTwitterConnected = false;
		}
	}

	public static void connectTwitter(String pin)
	{
		if (pin.length() == 0)
			return;

		try
		{
			accessToken = twitter.getOAuthAccessToken(requestToken, pin);
			storeAccessToken(TWITTER_WHO, accessToken.getToken(), UtilsStride.accessToken.getTokenSecret());
			synchronized (isTwitterConnected)
			{
				isTwitterConnected = true;
			}
			insertInDB(StrideDB.MATCH_U, new UsersItem(0, twitter.getScreenName(), "Twitter", "default", ""));
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

	public static String initTwitter4j()
	{
		try
		{
			synchronized (isTwitterConnected)
			{
				isTwitterConnected = false;
				twitter = new TwitterFactory().getInstance();
				twitter.setOAuthConsumer(OAUTH_KEY, OAUTH_SECRET);
				requestToken = twitter.getOAuthRequestToken();
				return requestToken.getAuthorizationURL();
			}
		}
		catch (TwitterException e)
		{
			e.printStackTrace();
		}
		return null;
	}

	public static String getUserName()
	{
		if (userName != "")
			return userName;

		// try twitter name
		boolean conn;
		synchronized (isTwitterConnected)
		{
			conn = isTwitterConnected;
		}
		if (conn)
		{
			try
			{
				userName = twitter.getScreenName();
				return userName;
			}
			catch (IllegalStateException e)
			{
				e.printStackTrace();
			}
			catch (TwitterException e)
			{
				e.printStackTrace();
			}
		}

		synchronized (fbName)
		{
			if (fbName != "")
			{
				userName = fbName;
				return userName;
			}
		}
		return "Gigi";
	}

	public static void disconnectFacebook()
	{
		synchronized (isFacebookConnected)
		{
			SessionEvents.onLogoutBegin();
			if (mAsyncRunner != null)
				mAsyncRunner.logout(mainActivity, new LogoutRequestListener());
			isFacebookConnected = false;
			fbName = "";
		}
	}

	public static void addTrackToDB(long distance, long time)
	{
		final ContentResolver cr = mainActivity.getContentResolver();
		final ContentValues values = new ContentValues();

		totalDistance = distance;
		totalTime = time;
		String trackName = recognizeTrack(pathPoints);
		if (trackName == null)
		{
			trackName = "track " + runningName;
			insertInDB(StrideDB.MATCH_T, new TracksItem(0, trackName, (int) totalDistance / 1000, "", "summer time"));
		}

		values.put(StrideDB.NAME_R, runningName);
		values.put(StrideDB.USERNAME_R, getUserName());
		values.put(StrideDB.TOPSPEED_R, (float) totalDistance / ((float) totalTime / 3.6));
		values.put(StrideDB.LENGTH_R, totalDistance / 1000);
		values.put(StrideDB.TRACKNAME_R, trackName);
		values.put(StrideDB.TIME_R, totalTime / 3600);
		values.put(StrideDB.DATE_R, (new Date()).getTime());
		values.put(StrideDB.LAPS_R, 1);
		values.put(StrideDB.DETAILS_R, "none");
		cr.insert(StrideDB.CONTENT_URI_RESULTS, values);
		resultsChanged = true;

	}

	private static String recognizeTrack(ArrayList<GePoint> pathPoints2)
	{
		return null;
	}

	private static class LogoutRequestListener extends BaseRequestListener
	{
		public void onComplete(String response)
		{
			SessionEvents.onLogoutFinish();
		}
	}

	private static class SessionListener implements AuthListener, LogoutListener
	{

		public void onAuthSucceed()
		{
			SessionStore.save(mFacebook, mainActivity);
			synchronized (isFacebookConnected)
			{
				isFacebookConnected = true;
			}
		}

		public void onAuthFail(String error)
		{
		}

		public void onLogoutBegin()
		{
		}

		public void onLogoutFinish()
		{
			SessionStore.clear(mainActivity);
			synchronized (isFacebookConnected)
			{
				isFacebookConnected = false;
			}
		}
	}

	public static void setFacebookConnected()
	{
		synchronized (isFacebookConnected)
		{
			isFacebookConnected = true;
		}
	}

	public static String getFbName()
	{
		synchronized (fbName)
		{
			return fbName;
		}
	}

	public static void setFbName(String name)
	{
		synchronized (fbName)
		{
			fbName = name;
		}
	}

	public static void removeFromDB(int match_uri, Object item)
	{
		final ContentResolver cr = mainActivity.getContentResolver();
		switch (match_uri)
		{
		case StrideDB.MATCH_R:
			MapListViewItem mapItem = (MapListViewItem) item;
			cr.delete(StrideDB.CONTENT_URI_RESULTS, StrideDB.ID_R + "=" + mapItem.getId(), null);
			break;
		case StrideDB.MATCH_T:
			break;
		case StrideDB.MATCH_U:
			UsersItem uItem = (UsersItem) item;
			cr.delete(StrideDB.CONTENT_URI_USERS, StrideDB.ID_U + "=" + uItem.getId(), null);
			break;
		case StrideDB.MATCH_I:
			break;
		case StrideDB.MATCH_P:
			break;
		case StrideDB.MATCH_M:
			break;
		}
	}

	public static void insertInDB(int match_uri, Object item)
	{
		final ContentResolver cr = mainActivity.getContentResolver();
		ContentValues values = new ContentValues();
		switch (match_uri)
		{
		case StrideDB.MATCH_R:
//			MapListViewItem mapItem = (MapListViewItem) item;
			break;
		case StrideDB.MATCH_T:
			TracksItem tItem = (TracksItem) item;
			values.put(StrideDB.NAME_T, tItem.getName());
			values.put(StrideDB.LENGTH_T, tItem.getLenght());
			values.put(StrideDB.GPX_T, tItem.getGpx());
			values.put(StrideDB.DETAILS_T, tItem.getDetails());
			cr.insert(StrideDB.CONTENT_URI_TRACKS, values);
			break;
		case StrideDB.MATCH_U:
		{
			UsersItem userItem = (UsersItem) item;
			Cursor cursoru = mainActivity.managedQuery(StrideDB.CONTENT_URI_USERS, null, StrideDB.NAME_U + " = '"
					+ userItem.getName() + "'", null, null);
			if (cursoru.moveToFirst() != false)
			{
				cursoru.close();
				return;
			}
			cursoru.close();

			if (userItem.getPlaylist() == "")
				userItem.setPlaylist("default");
			values.put(StrideDB.NAME_U, userItem.getName());
			values.put(StrideDB.NETWORK_U, userItem.getNetwork());
			values.put(StrideDB.PLAYLIST_U, userItem.getPlaylist());
			values.put(StrideDB.DETAILS_U, userItem.getDetails());
			cr.insert(StrideDB.CONTENT_URI_USERS, values);

			// add playlist
			String playlist = userItem.getPlaylist();
			Cursor cursor = mainActivity.managedQuery(StrideDB.CONTENT_URI_PLAYLISTS, null, StrideDB.NAME_P + " = '"
					+ playlist + "'", null, null);
			if (cursor.moveToFirst() == false)
			{
				insertInDB(StrideDB.MATCH_P, new PlaylistsItem(playlist, ""));
			}
			cursor.close();
		}
			break;
		case StrideDB.MATCH_I:
			break;
		case StrideDB.MATCH_P:
			PlaylistsItem playItem = (PlaylistsItem) item;
			values.put(StrideDB.NAME_P, playItem.getName());
			values.put(StrideDB.DETAILS_P, playItem.getDetails());
			cr.insert(StrideDB.CONTENT_URI_PLAYLISTS, values);
			break;
		case StrideDB.MATCH_M:
		{
			MusicItem musicItem = (MusicItem) item;
			values.put(StrideDB.SONG_M, musicItem.getSong());
			values.put(StrideDB.SINGER_M, musicItem.getSinger());
			values.put(StrideDB.FILE_M, musicItem.getFile());
			values.put(StrideDB.PLAYLIST_M, musicItem.getPlaylist());
			values.put(StrideDB.DETAILS_M, musicItem.getDetails());
			cr.insert(StrideDB.CONTENT_URI_MUSIC, values);

			// add playlist
			String playlist = musicItem.getPlaylist();
			Cursor cursor = mainActivity.managedQuery(StrideDB.CONTENT_URI_PLAYLISTS, null, StrideDB.NAME_P + " = '"
					+ playlist + "'", null, null);
			if (cursor.moveToFirst() == false)
			{
				insertInDB(StrideDB.MATCH_P, new PlaylistsItem(playlist, ""));
			}
			cursor.close();
		}
		}
	}

	public static void fillRandomDB(int match_uri, int count)
	{
		final Random rand = new Random();
		final ContentResolver cr = mainActivity.getContentResolver();
		final ContentValues values = new ContentValues();

		switch (match_uri)
		{
		case StrideDB.MATCH_R:
			for (int i = 0; i < count; i++)
			{
				int myRand = rand.nextInt(300);
				values.put(StrideDB.NAME_R, "name_" + myRand);
				values.put(StrideDB.USERNAME_R, "username_" + myRand);
				values.put(StrideDB.TRACKNAME_R, "trackname_" + myRand);
				values.put(StrideDB.DATE_R, myRand * 1000);
				values.put(StrideDB.LAPS_R, "laps_" + myRand);
				values.put(StrideDB.LENGTH_R, myRand);
				values.put(StrideDB.TIME_R, myRand);
				values.put(StrideDB.TOPSPEED_R, myRand);
				values.put(StrideDB.DETAILS_R, "details_" + myRand);
				cr.insert(StrideDB.CONTENT_URI_RESULTS, values);
				values.clear();
			}
			break;
		case StrideDB.MATCH_T:
			for (int i = 0; i < count; i++)
			{
				int myRand = rand.nextInt(300);
				values.put(StrideDB.NAME_T, "name_" + myRand);
				values.put(StrideDB.LENGTH_T, myRand);
				values.put(StrideDB.GPX_T, "gpx_" + myRand);
				values.put(StrideDB.DETAILS_T, "details_" + myRand);
				cr.insert(StrideDB.CONTENT_URI_TRACKS, values);
				values.clear();
			}
			break;
		case StrideDB.MATCH_U:
			for (int i = 0; i < count; i++)
			{
				int myRand = rand.nextInt(2);
				values.put(StrideDB.NAME_U, "name_" + myRand);
				values.put(StrideDB.NETWORK_U, "netw_" + myRand);
				values.put(StrideDB.PLAYLIST_U, "default" + myRand);
				values.put(StrideDB.DETAILS_U, "details_" + myRand);
				cr.insert(StrideDB.CONTENT_URI_USERS, values);
				values.clear();
			}
			break;
		case StrideDB.MATCH_I:
			for (int i = 0; i < count; i++)
			{
				int myRand = rand.nextInt(300);
				values.put(StrideDB.NAME_I, "name_" + myRand);
				values.put(StrideDB.USERNAME_I, "username_" + myRand);
				values.put(StrideDB.DATE_I, "date_" + myRand);
				values.put(StrideDB.LENGTH_I, myRand);
				values.put(StrideDB.TIME_I, myRand);
				values.put(StrideDB.TOPSPEED_I, myRand);
				values.put(StrideDB.DETAILS_I, "details_" + myRand);
				cr.insert(StrideDB.CONTENT_URI_IMPORTS, values);
				values.clear();
			}
			break;
		case StrideDB.MATCH_P:
			for (int i = 0; i < count; i++)
			{
				int myRand = rand.nextInt(300);
				values.put(StrideDB.NAME_P, "name_" + myRand);
				values.put(StrideDB.DETAILS_P, "details_" + myRand);
				cr.insert(StrideDB.CONTENT_URI_PLAYLISTS, values);
				values.clear();
			}
			break;
		case StrideDB.MATCH_M:
			for (int i = 0; i < count; i++)
			{
				int myRand = rand.nextInt(300);
				values.put(StrideDB.SONG_M, "song_" + myRand);
				values.put(StrideDB.SINGER_M, "singer_" + myRand);
				values.put(StrideDB.PLAYLIST_M, "playlist_" + myRand);
				values.put(StrideDB.FILE_M, "file_" + myRand);
				values.put(StrideDB.DETAILS_M, "details_" + myRand);
				cr.insert(StrideDB.CONTENT_URI_MUSIC, values);
				values.clear();
			}
			break;
		}
	}

	public static void clearTable(int match_uri)
	{
		final ContentResolver cr = mainActivity.getContentResolver();
		switch (match_uri)
		{
		case StrideDB.MATCH_R:
			cr.delete(StrideDB.CONTENT_URI_RESULTS, null, null);
			break;
		case StrideDB.MATCH_T:
			cr.delete(StrideDB.CONTENT_URI_TRACKS, null, null);
			break;
		case StrideDB.MATCH_U:
			cr.delete(StrideDB.CONTENT_URI_USERS, null, null);
			break;
		case StrideDB.MATCH_I:
			cr.delete(StrideDB.CONTENT_URI_IMPORTS, null, null);
			break;
		case StrideDB.MATCH_P:
			cr.delete(StrideDB.CONTENT_URI_PLAYLISTS, null, null);
			break;
		case StrideDB.MATCH_M:
			cr.delete(StrideDB.CONTENT_URI_MUSIC, null, null);
			break;
		}
	}

	public static void playMusic()
	{
		new Thread(new Runnable()
		{
			@Override
			public void run()
			{
				String username = getUserName();
				String playlist = "default";
				String file = null;
				// citeste playlist din DB
				Cursor cursor = mainActivity.managedQuery(StrideDB.CONTENT_URI_USERS, null, StrideDB.NAME_U + " = '"
						+ username + "'", null, null);
				if (cursor.moveToNext())
				{
					final int playlist_index = cursor.getColumnIndex(StrideDB.PLAYLIST_U);
					playlist = cursor.getString(playlist_index);
				}
				cursor.close();

				cursor = mainActivity.managedQuery(StrideDB.CONTENT_URI_MUSIC, null, StrideDB.PLAYLIST_M + " = '"
						+ playlist + "'", null, null);
				while (cursor.moveToNext())
				{
					final int file_index = cursor.getColumnIndex(StrideDB.FILE_M);
					file = cursor.getString(file_index);
					if (file != currentMP)
						break;
				}
				cursor.close();
				if (file != null)
				{
					startTrack(file, playlist);
				}
			}

		}).start();
	}

	private static void startTrack(String file, final String playlist)
	{
		currentMP = file;
		mp = MediaPlayer.create(mainActivity, Uri.fromFile(new File(file)));
		try
		{
			try
			{
				mp.prepare();
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
			mp.start();
			mp.setOnCompletionListener(new OnCompletionListener()
			{
				@Override
				public void onCompletion(MediaPlayer mp)
				{
					Cursor cursorp = mainActivity.managedQuery(StrideDB.CONTENT_URI_MUSIC, null, StrideDB.PLAYLIST_M
							+ " = '" + playlist + "'", null, null);
					String file2 = null;
					while (cursorp.moveToNext())
					{
						final int file_index = cursorp.getColumnIndex(StrideDB.FILE_M);
						file2 = cursorp.getString(file_index);
						if (file2 != currentMP)
							break;
					}
					cursorp.close();
					if (file2 != null)
						startTrack(file2, playlist);
				}
			});
		}
		catch (Exception e)
		{
			mp.stop();
			mp.release();
			e.printStackTrace();
		}
	}

	public static void stopMusic()
	{
		currentMP = null;
		try
		{
			mp.stop();
			mp.release();
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
}
